package org.jeecg.modules.cascv.image.controller;

import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.lineparser.Line;
import org.jeecg.common.lineparser.LineParser;
import org.jeecg.config.TaskExecutePool;
import org.jeecg.modules.cascv.image.service.impl.MergeVideoService;
import org.jeecg.modules.cascv.image.service.video.VideoService;
import org.jeecg.modules.cascv.image.util.LaptopConstant;
import org.jeecg.modules.cascv.image.util.LaptopUtil;
import org.jeecg.modules.cascv.image.util.MergeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;

/**
 * @Description: ids图片播放
 * @Author: jeecg-boot
 * @Date: 2022-08-31
 * @Version: V1.0
 */
@Slf4j
@Api(tags = "视频播放")
@RestController
@RequestMapping("/video")
public class GmvVideoController {
    @Value("${jeecg.path.upload}")
    private String upLoadPath;
    @Value("${srsAddress}")
    private String srsAddress;
    @Autowired
    private MergeVideoService mergeVideoService;
    @Autowired
    private VideoService videoService;
    @Autowired
    private TaskExecutePool taskExecutePool;

    private AtomicBoolean test_lock = new AtomicBoolean(false);

    @ApiOperation(value = "开始播放", notes = "开始播放") //前端请求流媒体，流媒体请求后端
    @RequestMapping(value = "/play", produces = "application/json;charset=utf-8")
    @ResponseBody
    public Result<?> play(HttpServletRequest req, String idsName, String fileId, Long ts, String userId) {

        String key = StringUtils.isNotEmpty(idsName) ? idsName : fileId;

        AtomicInteger version = LaptopConstant.clientVersionMap.get(userId); //客户端版本号
        if (version == null) {
            version = new AtomicInteger(0);
            LaptopConstant.clientVersionMap.put(userId, version); //version版本号 来区分
        }
        LaptopConstant.startOrStop.put(key, 1);  // 初始化
        LinkedList<String> secondIndex = LaptopConstant.secondIndexCache.getIfPresent(key); //建立索引
        if (secondIndex == null) {
            LaptopConstant.secondIndexCache.put(key, new LinkedList<>());  //进度放到共享内存里面去 因为拉流的过程调用的c++方法 需要回调
        }

        String webrtcUrl = null;
        int newVersion = version.incrementAndGet(); //保证原子性 version+1;
        //后端推的是rtmp协议  这边是
        webrtcUrl = "webrtc://" + srsAddress + "/live/livestream/" + key + "/" + userId + "/" + newVersion;

        videoService.play(userId, idsName, key, newVersion, ts);

        ///home/poac/env_tool/srs
//        String webrtcUrl = "web://124.221.248.158:1935/live/livestream/" + key + "/" + version;
        //webrtc://124.221.248.158/live/livestream/TGTHYY0501_061H_31_HMRCSAPP2H/4
        return Result.OK(webrtcUrl);
    }

    @ApiOperation(value = "视频播放-进度条info", notes = "视频播放-进度条info")
    @RequestMapping(value = "/count", produces = "application/json;charset=utf-8")
    @ResponseBody
    public Result<?> queryPageCount(String idsName, String fileId,
                                    HttpServletRequest req) {


        String key = StringUtils.isNotEmpty(idsName) ? idsName : fileId;
        //log.info("key:===>"+key);
        LinkedList<String> list = LaptopConstant.secondIndexCache.getIfPresent(key);
        if (CollectionUtils.isEmpty(list)) {
            return Result.OK();
        }
        Long[][] longs = MergeUtil.mergeRange(list, 10);
        return Result.OK(longs);
    }

    @ApiOperation(value = "文件上传", notes = "文件上传")
    @PostMapping(value = "/uploadFile")
    @CrossOrigin
    public Result<?> uploadFile(HttpServletRequest request) {
        Result<String> result = new Result<>();
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        MultipartFile file = multipartRequest.getFile("file");

        if (file == null) return Result.error("文件不能为空！");
        FileOutputStream out = null;
        String fileId = IdWorker.get32UUID();
        String filePath = upLoadPath + File.separator + file.getOriginalFilename();
        LaptopConstant.filePathMap.put(fileId, filePath);
        FileUtil.touch(filePath); //创建文件及其父目录，如果这个文件存在，直接返回这个文件 此方法不对File对象类型做判断，如果File不存在，无法判断其类型

        try {
            out = new FileOutputStream(new File(filePath));
            out.write(file.getBytes());
            out.flush();
            LaptopConstant.threadMap.put(fileId, true);
//            Thread thread = new Thread() {
//                @Override
//                public void run() {
//                }
//            };
//            thread.start();
        } catch (Exception e) {
            log.error("文件上传失败！", e);
           return Result.error("文件上传失败!");
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        Cache<Integer, Long> indexCache = Caffeine.newBuilder().build();;
        LaptopConstant.fileIndexCache.put(fileId, indexCache);
        LaptopConstant.secondIndexCache.put(fileId,new LinkedList<>());

        Cache<Integer, Long> finalIndexCache = indexCache;

        taskExecutePool.threadPoolTaskExecutor().execute(new Runnable() {
            @Override
            public void run() {

                LineParser parser = new LineParser(Integer.MAX_VALUE, 0); //初始化读取工具
                Path path = Paths.get(filePath);
                Charset cs = StandardCharsets.UTF_8;
                try {
                    parser.forEach(path, cs, new Consumer<Line>() {
                                @Override
                                public void accept(Line line) {
                                    JSONObject dataItem = JSON.parseObject(line.getContent().toString());
                                    String tableName = dataItem.getString("tableName");
                                    String secondStr = dataItem.getString("second");
                                    dataItem = dataItem.getJSONObject("Content");

                                    //A1_VGR_MICU_APP14DATA_8_11_1
                                    //String secondStr = dataItem.getString(LaptopConstant.SECOND_FIELD_MAP.get(tableName));
                                    //Long second = LaptopUtil.getSecondTime(secondStr.split(";")[1]);
                                    Long second = Long.parseLong(secondStr);
                                    Long cache_offset = finalIndexCache.getIfPresent(second);
                                    if (cache_offset == null) { //
                                        finalIndexCache.put(second.intValue(), line.getOffset()); //取到秒值 还有文件这一行的索offset 设置一个偏移量 缓存起来
                                    }
                                    System.out.println("fileId = " + fileId);
                                    LinkedList<String> secondIndexCache = LaptopConstant.secondIndexCache.getIfPresent(fileId);
                                    //1,1   2,2   3,3  ==>>  1,3
                                    secondIndexCache.add(second + "," + second);
                                    //时间的范围
                                    if (secondIndexCache.size() > 20) {
                                        Long[][] longs = MergeUtil.mergeRange(secondIndexCache, 10);
                                        secondIndexCache = new LinkedList<>();
                                        for (Long[] aLong : longs) {
                                            secondIndexCache.add(aLong[0] + "," + aLong[1]);
                                        }
                                        //secondIndexCache: 进度条
                                        LaptopConstant.secondIndexCache.put(fileId, secondIndexCache);
                                    }
                                }
                            }
                    );
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });


        result.setResult(fileId);
        result.success("操作成功2");
        return result;
    }


    public void videoByFile(String fileId) {
        try {
            String filePath = LaptopConstant.filePathMap.get(fileId);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("添加视屏图片帧失败", e);
        }
    }


    @ApiOperation(value = "心跳接口", notes = "心跳接口")
    @GetMapping(value = "/heartbeat")
    public Result<?> heartbeat(String fileId) {
        Result<?> result = new Result<>();
        LaptopConstant.timeMap.put(fileId, System.currentTimeMillis() + 1000 * 10);
        result.success("操作成功");
        return result;
    }


    @ApiOperation(value = "开始暂停接口", notes = "开始暂停接口")
    @GetMapping(value = "/startOrStop")
    public Result<?> startOrStop(String fileId, Integer flag) {
        Result<?> result = new Result<>();
        if (flag == null) {
            flag = 1;
        }
        LaptopConstant.startOrStop.put(fileId, flag);
        result.success("操作成功");
        return result;
    }


    @ApiOperation(value = "ids图片播放-实时测试接口", notes = "ids图片播放-实时测试接口")
    @RequestMapping(value = "/testReal") //测试接口调用这个
    public Result<?> test(HttpServletRequest request, final String idsName) throws Exception {

        boolean lock = test_lock.compareAndSet(false, true); //开始为true
        if (!lock) {
            return Result.OK();
        }

//        /data/workspace/laptop-java/files
//        String filePath = "//files//TGTHYY0401_090H_31_CMPRAPP5.txt";
        new Thread(new Runnable() {
            public void run() {
                try {
                    log.info("idsname==>" + idsName); //日志打印
                    //  String filePath = "//files//"+idsName +".txt";
                    String filePath = "D:/files/t2.h264";
                    log.info("filePath" + filePath);

                    for (int i = 0; i < 1; i++) {//之前循环100次 现在1次
                        RandomAccessFile randomAccessFile = new RandomAccessFile(filePath, "r");
                        while (true) {
                            String jsonStr = randomAccessFile.readLine();
                            if (jsonStr == null) {
                                log.info("while循环结束！！！");
                                break;
                            }
                            //避免读取乱码
                            jsonStr = new String(jsonStr.getBytes("ISO-8859-1"), "utf-8");
                            JSONObject jsonObject = JSONObject.parseObject(jsonStr); //将字符串转为JSONObject
                            mergeVideoService.merge(jsonObject, null, null);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    test_lock.set(false);
                }
            }
        }).start();
        return Result.OK();
    }


}
